package com.library.xtype;

import java.lang.ref.WeakReference;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import static com.library.xtype.GlobalNuwaPool.getItemPropertys;

/**
 * 在此写用途
 *
 * @author: zhiwei
 * @date: 2016-12-28 13:09
 * @version: 9.1.0
 */
public class NuwaRecyclerViewAdapter extends RecyclerView.Adapter<WrapRecyclerViewHolder> implements INuwaLifecycle,
    IAdapter {
    NuwaItemPool mNuwaPoolDalegate;
    List mDataList = new ArrayList();
    SparseArray<WeakReference<INuwaItemBinder>> mNuwaViewCache = new SparseArray<>(20);
    LayoutInflater mInflater;
    View.OnClickListener mOnClickListener;

    public NuwaRecyclerViewAdapter() {
        this(new NuwaItemPool());
    }

    public NuwaRecyclerViewAdapter(NuwaItemPool manager) {
        mNuwaPoolDalegate = manager;
    }

    public NuwaRecyclerViewAdapter setNuwaPoolDalegate(NuwaItemPool nuwaPoolDalegate) {
        if (mNuwaPoolDalegate != null) {
            Collection<ItemProperty> itemProperties = mNuwaPoolDalegate.getItemPropertys();
            for (ItemProperty property : itemProperties) {
                register(property.getItemBinderClass());
            }
        }
        mNuwaPoolDalegate = nuwaPoolDalegate;
        return this;
    }

    public void setOnClickListener(View.OnClickListener onClickListener) {
        mOnClickListener = onClickListener;
    }

    /**
     * 方法将废弃，请使用
     * @see #register(Class <T>)
     *
     * @param voClazz vo
     * @param binder binder extender INuwaItemBinder
     * @param <T>
     */
    @Deprecated
    public <T extends INuwaItemBinder> void register(@NonNull Class voClazz, @NonNull Class<T> binder) {
        mNuwaPoolDalegate.register(voClazz, binder);
    }

    /**
     * 此方法会自动查找 INuwaItemBinder 类中对应使用的VO。
     *
     * 注意使用此方法，Nuwa中一个VO只能对应一个Binder。
     * @param binder binder
     * @param <T>
     */
    public <T extends INuwaItemBinder> void register(@NonNull Class<T> binder) {
        Type genType = binder.getGenericSuperclass();
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
        Class voClazz = (Class) params[0];
        mNuwaPoolDalegate.register(voClazz, binder);
    }


    /**
     * 应用全局的NuwaItemPool
     */
    public void applyGlobalMultiTypePool() {
        Collection<ItemProperty> itemProperties = getItemPropertys();
        for (ItemProperty property : itemProperties) {
            register(property.getItemVOClass(), property.getItemBinderClass());
        }
    }

    @Override
    public void onViewRecycled(WrapRecyclerViewHolder holder) {
        super.onViewRecycled(holder);
        holder.onDestroy();
    }

    @Override
    public WrapRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        INuwaItemBinder nuwaItemView = mNuwaPoolDalegate.createItemView(parent.getContext(), viewType);
        // create nullable item view
        if (nuwaItemView == null) {
            nuwaItemView = new NullableIBinder();
        }
        if (mInflater == null) {
            mInflater = LayoutInflater.from(parent.getContext());
        }
        View contentView = nuwaItemView.onCreateView(null, parent, mInflater);
        WrapRecyclerViewHolder nuwaViewHolder = new WrapRecyclerViewHolder(contentView, nuwaItemView);
        mNuwaViewCache.put(nuwaItemView.hashCode(), new WeakReference<INuwaItemBinder>(nuwaItemView));
        if (mOnClickListener != null) {
            nuwaItemView.setOnClickListener(mOnClickListener);
        }
        return nuwaViewHolder;
    }

    @Override
    public void onBindViewHolder(WrapRecyclerViewHolder holder, int position) {
        holder.onBindView(position, getItem(position));
    }


    @Override
    public int getItemViewType(int position) {
        return mNuwaPoolDalegate.getItemViewType(getItem(position));
    }

    @Override
    public int getItemCount() {
        return mDataList.size();
    }


    @Override
    public void onCreate() {
        for (int i = 0, nsize = mNuwaViewCache.size(); i < nsize; i++) {
            WeakReference<INuwaItemBinder> weakView = mNuwaViewCache.valueAt(i);
            INuwaItemBinder binder = weakView.get();
            if (binder != null) {
                binder.onCreate();
            }
        }
    }

    @Override
    public void onStart() {
        for (int i = 0, nsize = mNuwaViewCache.size(); i < nsize; i++) {
            WeakReference<INuwaItemBinder> weakView = mNuwaViewCache.valueAt(i);
            INuwaItemBinder binder = weakView.get();
            if (binder != null) {
                binder.onStart();
            }
        }
    }

    @Override
    public void onResume() {
        for (int i = 0, nsize = mNuwaViewCache.size(); i < nsize; i++) {
            WeakReference<INuwaItemBinder> weakView = mNuwaViewCache.valueAt(i);
            INuwaItemBinder binder = weakView.get();
            if (binder != null) {
                binder.onResume();
            }
        }
    }

    @Override
    public void onPause() {
        for (int i = 0, nsize = mNuwaViewCache.size(); i < nsize; i++) {
            WeakReference<INuwaItemBinder> weakView = mNuwaViewCache.valueAt(i);
            INuwaItemBinder binder = weakView.get();
            if (binder != null) {
                binder.onPause();
            }
        }
    }

    @Override
    public void onStop() {
        for (int i = 0, nsize = mNuwaViewCache.size(); i < nsize; i++) {
            WeakReference<INuwaItemBinder> weakView = mNuwaViewCache.valueAt(i);
            INuwaItemBinder binder = weakView.get();
            if (binder != null) {
                binder.onStop();
            }
        }
    }

    @Override
    public void onDestroy() {
        for (int i = 0, nsize = mNuwaViewCache.size(); i < nsize; i++) {
            WeakReference<INuwaItemBinder> weakView = mNuwaViewCache.valueAt(i);
            INuwaItemBinder binder = weakView.get();
            if (binder != null) {
                binder.onDestroy();
            }
        }
        mNuwaViewCache.clear();
        mNuwaPoolDalegate.destory();
    }

    @Override
    public void clearData() {
        if (mDataList != null) {
            mDataList.clear();
            try {
                //Cannot call this method while RecyclerView is computing a layout or scrolling
                notifyDataSetChanged();
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void flushData(List data) {
        if (mDataList != null) {
            mDataList.clear();
        }
        if (data != null) {
            if (mDataList == null) {
                mDataList = new ArrayList(data);
            } else {
                mDataList.addAll(data);
            }
        }
        try {
            //Cannot call this method while RecyclerView is computing a layout or scrolling
            notifyDataSetChanged();
        } catch (Throwable e) {
            e.printStackTrace();
        }

    }

    @Override
    public void appendData(List data) {
        if (mDataList == null) {
            flushData(data);
        } else if (data != null) {
            mDataList.addAll(data);
            try {
                //Cannot call this method while RecyclerView is computing a layout or scrolling
                notifyDataSetChanged();
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public Object getItem(int position) {
        return mDataList.get(position);
    }

    @Override
    public int getRealCount() {
        return getItemCount();
    }

    @Override
    public void removeData(Object data) {
        if (mDataList != null) {
            int index = mDataList.indexOf(data);
            if (index >= 0) {
                try {
                    mDataList.remove(index);
                    //Cannot call this method while RecyclerView is computing a layout or scrolling
                    notifyItemRemoved(index);
                } catch (Throwable e) {
                    e.printStackTrace();
                }
            }
        }
    }


    @Override
    public List getAllData() {
        return mDataList;
    }
}

